package com.example.qxfw.nyqx.service.impl;

import com.example.qxfw.common.entity.ny.CropGrowdateFcst;
import com.example.qxfw.common.entity.ny.StationInfo;
import com.example.qxfw.common.entity.zy.AgriProduct;
import com.example.qxfw.common.util.DateUtil;
import com.example.qxfw.mongodb.hy.entity.HyDocFile;
import com.example.qxfw.mongodb.hy.service.DocFileService;
import com.example.qxfw.nyqx.dto.FyqybParamDto;
import com.example.qxfw.nyqx.mapper.AgriProductMapper;
import com.example.qxfw.nyqx.service.CropGrowdateFcstService;
import com.example.qxfw.nyqx.service.CropGrowdateIndexlibService;
import com.example.qxfw.nyqx.service.DevelopmentPeriodPredictionService;
import com.example.qxfw.rcyw.service.StationInfoService;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.*;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import static com.example.qxfw.common.util.DocxUtil.replaceTextInParagraph;

@Service
public class DevelopmentPeriodPredictionServiceImpl implements DevelopmentPeriodPredictionService {

    @Autowired
    private StationInfoService stationInfoService;

    @Autowired
    private CropGrowdateFcstService cropGrowdateFcstService;

    @Autowired
    private CropGrowdateIndexlibService growdateIndexlibService;

    @Autowired
    private AgriProductMapper agriProductMapper;

    @Autowired
    private DocFileService docFileService;

    @Value("${filePath.docFilePath}")
    private String docFilePath;

    @Override
    public List<StationInfo> listByMainCrop(String mainCrop) {

        return stationInfoService.listByMainCrop(mainCrop);
    }

    @Override
    public String ybzz(FyqybParamDto fyqybParamDto) {
        //获取发育期前一个发育期
        List<String> growDateName = growdateIndexlibService.getGrowDateName(fyqybParamDto.getCropName());
        int index = 0;
        for (int i = 0; i < growDateName.size(); i++) {
            if (growDateName.get(i).equals(fyqybParamDto.getGrowdateName())) {
                index = i;
                break;
            }
        }
        //为第一个发育期，根据手动输入保存发育期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if (index == 0) {
            CropGrowdateFcst cropGrowdateFcst = new CropGrowdateFcst();
            cropGrowdateFcst.setStationid(fyqybParamDto.getStationId());
            cropGrowdateFcst.setCropname(fyqybParamDto.getCropName());
            cropGrowdateFcst.setType(fyqybParamDto.getType());
            cropGrowdateFcst.setYear(fyqybParamDto.getYear());
            cropGrowdateFcst.setGrowdatename(fyqybParamDto.getGrowdateName());
            cropGrowdateFcst.setForecastdate(fyqybParamDto.getForecastdate());
            //保存预报
            saveFcst(cropGrowdateFcst);
            return sdf.format(fyqybParamDto.getForecastdate());
        }

        String foreGrowName = growDateName.get(index - 1);
        List<CropGrowdateFcst> list1 = cropGrowdateFcstService.listByParam(String.valueOf(fyqybParamDto.getYear()),
                fyqybParamDto.getStationId(),
                fyqybParamDto.getType(),
                fyqybParamDto.getCropName(),
                foreGrowName);
        //上一个发育期为空
        if (list1.size() == 0) {
            return null;
        }
        //上个发育期预报时间
        Date foreForecastdate = list1.get(0).getForecastdate();
        //发育期相差天数
        int days = fyqybParamDto.getQwTemp() / (fyqybParamDto.getAvgTemp() - fyqybParamDto.getMinTemp());
        Date forecastdate = addDay(foreForecastdate, days);
        CropGrowdateFcst cropGrowdateFcst = new CropGrowdateFcst();
        cropGrowdateFcst.setStationid(fyqybParamDto.getStationId());
        cropGrowdateFcst.setCropname(fyqybParamDto.getCropName());
        cropGrowdateFcst.setType(fyqybParamDto.getType());
        cropGrowdateFcst.setYear(fyqybParamDto.getYear());
        cropGrowdateFcst.setGrowdatename(fyqybParamDto.getGrowdateName());
        cropGrowdateFcst.setForecastdate(forecastdate);
        //保存预报
        saveFcst(cropGrowdateFcst);
        return sdf.format(forecastdate);
    }

    @Override
    public Object cropGrowdateforecast(String year, String month, String day, String yxjw, String pjwd, String fyqTime, int temp, String nsZstation, String fyqName, String time, String type, String cropsName, String maker) {
        String fyqtime = "";//上一个发育期
        //获取发育期前一个发育期
        List<String> growDateName = growdateIndexlibService.getGrowDateName(cropsName);
        int index = 0;
        for (int i = 0; i < growDateName.size(); i++) {
            if (growDateName.get(i).equals(fyqName)) {
                index = i;
                break;
            }
        }

        if (index == 0) {
            List<String> growdateList = cropGrowdateFcstService.getForecastDate(year, nsZstation, type, cropsName, fyqName);
            if (growdateList.size() > 0)
                fyqtime = growdateList.get(0);
        } else {
            List<String> growdateList = cropGrowdateFcstService.getForecastDate1(year, nsZstation, type, cropsName);
            if (growdateList.size() > 0)
                fyqtime = growdateList.get(0);
        }
        //文档名称 : 20230706双季晚稻预报文档.docx
        String docName = year + month + day + cropsName + "预报文档.docx";
        //生成的文档的产品类型
        String productType = "发育期预报";
        //预报时间
        Timestamp forecastTime = DateUtil.localDateTimeToTimestamp(DateUtil.stringToLocalDateTime(fyqTime));
        //文档制作时间
        Timestamp makeTime = DateUtil.localDateTimeToTimestamp(LocalDateTime.now());
        //查询数据
        List<String> growdateList = cropGrowdateFcstService.getForecastDate(year, nsZstation, type, cropsName, fyqtime);
        //判断是否有数据
        if (growdateList == null) {
            return "无数据，无法生成文档，请联系管理员";
        }

        //查询agri_product表是否已经存在
        Integer id = agriProductMapper.selectId(docName, productType, forecastTime, makeTime, maker);

        if (id == null) {
            //查询出agri_product表没有该文档
            //新建agriProduct类并设置数据
            AgriProduct agriProduct = new AgriProduct();
            //文档名称
            agriProduct.setProductname(docName);
            //产品类型
            agriProduct.setProducttype(productType);
            //预报时间
            agriProduct.setForecasttime(forecastTime);
            //制作时间
            agriProduct.setMaketime(makeTime);
            //制作人
            agriProduct.setMaker(maker);
            //状态
            agriProduct.setState("0");
            //插入数据到agri_product表，并返回插入的结果
            int insert = agriProductMapper.insert(agriProduct);
            //如果插入数据成功
            if (insert > 0) {
                //将数据写入word文档
                Integer id1 = agriProductMapper.selectId(docName, productType, forecastTime, makeTime, maker);
                return docxToMongoDb(year, month, day, yxjw,
                        pjwd, fyqTime, fyqtime, temp, nsZstation,
                        fyqName, time, type, cropsName, id1, productType);
            } else {
                return "数据存入agri_product表失败，请联系管理员";
            }
        } else {
            //当pg数据库中有此信息时，查询mongo数据库中的信息
            HyDocFile docFileServiceById = docFileService.getById(String.valueOf(id));
            //mongo数据库中无此数据
            if (docFileServiceById == null) {
                Integer id1 = agriProductMapper.selectId(docName, productType, forecastTime, makeTime, maker);
                return docxToMongoDb(year, month, day, yxjw,
                        pjwd, fyqTime, fyqtime, temp, nsZstation,
                        fyqName, time, type, cropsName, id1, productType);
            } else {
                //mongo数据库中有此数据,则市界返回前端
                byte[] data = docFileServiceById.getData();
                HttpHeaders headers = new HttpHeaders();
                headers.setContentDispositionFormData("attachment", docName);
                headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
                headers.setContentLength(data.length);
                return new ResponseEntity<>(data, headers, HttpStatus.OK);
            }
        }
    }

    /************************
     * @Author : HuangDeYin Jolly
     * @Description : 将docx文件存入到mongo中
     * @return org.springframework.http.ResponseEntity<byte [ ]> :
     ************************/
    public ResponseEntity<byte[]> docxToMongoDb(String year, String month, String day, String yxjw, String pjwd, String fyqTime, String fyqtime, int temp, String nsZstation, String fyqName, String time, String type, String cropsName, Integer id, String productType) {
        ResponseEntity<byte[]> byteArrayResourceResponseEntity = dataToDocx(year, month, day, yxjw,
                pjwd, fyqTime, fyqtime, temp, nsZstation,
                fyqName, time, type, cropsName);
        if (byteArrayResourceResponseEntity.getStatusCode() == HttpStatus.OK) {
            byte[] byteArray = byteArrayResourceResponseEntity.getBody();
            // 保存进mongo
            HyDocFile hyDocFile = new HyDocFile();
            hyDocFile.setData(byteArray);
            hyDocFile.setId(String.valueOf(id));
            hyDocFile.setTable_name("agri_product");
            hyDocFile.setName(productType);
            HyDocFile save = docFileService.save(hyDocFile);
            return byteArrayResourceResponseEntity;
        } else {
            // 处理请求不成功的情况
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }


    public ResponseEntity<byte[]> dataToDocx(String year, String month, String day, String yxjw, String pjwd, String fyqTime, String fyqtime, int temp, String nsZstation, String fyqName, String time, String type, String cropsName) {
        //文档名称 : 2023070608灌溉预报文档.docx
        String docName = year + month + day + cropsName + "预报文档.docx";
        // 模板文件路径
        String templateFilePath = "templates/nqfwTemp/发育期预报.docx";
        // 输出文件路径
        String outputFilePath = docFilePath + "/" + docName;
        //模板中需要更换的字段
        String[] placeholders = new String[]{"【1】", "【2】", "【3】", "【4】", "【5】", "【6】", "【7】", "【8】", "【9】", "【10】", "【11】", "【12】", "【13】"};
        String[] replacements = new String[]{year, month, day, fyqTime, fyqtime, yxjw, String.valueOf(temp), pjwd, nsZstation, fyqName, time, type, cropsName};
        //打开模板文档
        try (InputStream templateStream = new ClassPathResource(templateFilePath).getInputStream();
             XWPFDocument document = new XWPFDocument(templateStream);
             FileOutputStream outputStream = new FileOutputStream(outputFilePath);
             FileInputStream inputStream = new FileInputStream(outputFilePath);
             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()
        ) {
            // 替换
            for (XWPFParagraph paragraph : document.getParagraphs()) {
                replaceTextInParagraph(paragraph, placeholders, replacements);
            }
            templateStream.close();
            // 将生成的文档保存到输出文件
            document.write(outputStream);

            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, bytesRead);
            }

            byte[] byteArray = byteArrayOutputStream.toByteArray();

            HttpHeaders headers = new HttpHeaders();
            headers.setContentDispositionFormData("attachment", docName);
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentLength(byteArray.length);

            return new ResponseEntity<>(byteArray, headers, HttpStatus.OK);

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 保存发育期预报
     *
     * @param cropGrowdateFcst
     */
    private void saveFcst(CropGrowdateFcst cropGrowdateFcst) {
        List<CropGrowdateFcst> list1 = cropGrowdateFcstService.listByParam(String.valueOf(cropGrowdateFcst.getYear()),
                cropGrowdateFcst.getStationid(),
                cropGrowdateFcst.getType(),
                cropGrowdateFcst.getCropname(),
                cropGrowdateFcst.getGrowdatename());
        //已经存在发育期预报则更新预报，否则插入预报
        if (list1.size() > 0) {
            cropGrowdateFcstService.update(cropGrowdateFcst);
        } else {
            cropGrowdateFcstService.save(cropGrowdateFcst);
        }
    }

    /**
     * 在原日期的基础上增加天数
     *
     * @param date
     * @param i
     * @return
     */
    public Date addDay(Date date, int i) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DATE, i);
        Date newDate = c.getTime();
        return newDate;
    }
}
